home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Internet Info 1994 March
/
Internet Info CD-ROM (Walnut Creek) (March 1994).iso
/
networking
/
ip
/
ka9q
/
src890906.arc
/
AX_MBX.C
< prev
next >
Wrap
C/C++ Source or Header
|
1989-08-19
|
16KB
|
641 lines
/* There are only two functions in this mailbox code that depend on the
underlying protocol, namely mbx_getname() and dochat(). All the other
functions can hopefully be used without modification on other stream
oriented protocols than AX.25 or NET/ROM.
However, please note that on AX.25 '\r' is used as EOL character while
on for instance TCP, '\r\n' is used. It would be handy if there were
a printf-compatible function that would take '\n' and map it to whatever
is the convention for the particular protocol in use.
SM0RGV 890506, most work done previously by W9NK
*/
#include <stdio.h>
#include <time.h>
#include <ctype.h>
#ifdef UNIX
#include <sys/types.h>
#endif
#include "global.h"
#include "ax_mbx.h"
#include "cmdparse.h"
#include "proc.h"
#include "socket.h"
#include "usock.h"
#include "ax25.h"
#include "smtp.h"
/*
#define MBDEBUG
*/
static struct mbx *Mbox[NUMMBX] ;
int Ax25mbox ;
static char Mbbanner[] = "[NET-$]\rWelcome to the %s TCP/IP Mailbox\r%s";
static char Mbmenu[] = "(C)hat, (S)end, (B)ye >\r" ;
static int donothing __ARGS((int argc,char *argv[],void *p));
static int dosend __ARGS((int argc,char *argv[],void *p));
static int dochat __ARGS((int argc,char *argv[],void *p));
static void domboxdisplay __ARGS((void));
static int dosid __ARGS((int argc,char *argv[],void *p));
static int dorevfwd __ARGS((int argc,char *argv[],void *p));
static struct mbx *newmbx __ARGS((void));
static int mbx_parse __ARGS((struct mbx *m));
static void mbx_getname __ARGS((struct mbx *m));
static int dobye __ARGS((int argc,char *argv[],void *p));
static int mbx_to __ARGS((int argc,char *argv[],void *p));
static int mbx_data __ARGS((struct mbx *m));
static struct cmds Mbcmds[] = {
"", donothing, 0, 0, NULLCHAR,
"s", dosend, 0, 0, NULLCHAR,
"send", dosend, 0, 0, NULLCHAR,
"chat", dochat, 0, 0, NULLCHAR,
"bye", dobye, 0, 0, NULLCHAR,
"[", dosid, 0, 0, NULLCHAR,
"f>", dorevfwd, 0, 0, NULLCHAR,
NULLCHAR, NULLFP, 0, 0, NULLCHAR,
};
int
dombox(argc, argv,p)
int argc ;
char *argv[] ;
void *p;
{
setbool(&Ax25mbox,"AX25 mailbox",argc,argv);
if (argc < 2)
domboxdisplay() ;
return 0;
}
static void
domboxdisplay()
{
int i ;
struct mbx *m ;
static char *states[] = {"NONE","CMD","SUBJ","DATA"} ;
printf("User State Type S#\n");
for (i = 0 ; i < NUMMBX ; i++)
if ((m = Mbox[i]) != NULLMBX) {
printf("%-10s %-4s %-7s %-3u\n",m->name,
states[m->state],Sestypes[m->type],m->user);
}
}
static struct mbx *
newmbx()
{
int i ;
struct mbx *m ;
for (i = 0 ; i < NUMMBX ; i++)
if (Mbox[i] == NULLMBX) {
if ((m = Mbox[i] = (struct mbx *)calloc(1,sizeof(struct mbx)))
== NULLMBX)
return NULLMBX ;
m->mbnum = i ;
return m ;
}
/* If we get here, there are no free mailbox sessions */
return NULLMBX ;
}
/* Incoming mailbox session */
void
mbx_incom(s,t,p)
int s;
void *t;
void *p;
{
int type; /* type of session when invoking "chat" */
int i;
char buf[30];
struct mbx *m ;
type = (int)t;
sockowner(s,Curproc); /* We own it now */
sprintf(buf,"open %s MBOX",Sestypes[type]);
log(s,buf);
if ((m = newmbx()) == NULLMBX) {
usprintf(s,"Too many mailbox sessions\r");
close_s(s) ; /* no memory! */
return ;
}
m->user = s;
m->type = type;
m->state = MBX_CMD ; /* start in command state */
mbx_getname(m); /* get the name of the remote station */
/* Now say hi */
usprintf(s,Mbbanner,Hostname,Mbmenu);
while (recvline(s,m->line,MBXLINE) != -1) {
if (m->line[0] != '\n' && m->line[0] != '\r'){
i = mbx_parse(m);
if (i == -1)
usprintf(s,"Huh?\r");
if (i == 1)
usprintf(s,"Bad syntax.\r");
}
usprintf(s,(m->sid & MBX_SID) ? ">\r" : Mbmenu);
m->state = MBX_CMD;
}
free(m->to) ;
free(m->tofrom) ;
free(m->tomsgid) ;
Mbox[m->mbnum] = NULLMBX ;
free((char *)m) ;
}
/* "twocmds" defines the MBL/RLI two-letter commands, eg. "SB", "SP" and so on.
They have to be treated specially since cmdparse() wants a space between
the actual command and its arguments.
"SP FOO" is converted to "s foo" and the second command letter is saved
in m->stype. Longer commands like "SEND" are unaffected, except for
commands starting with "[", i.e. the SID, since we don't know what it will
look like.
*/
static char twocmds[] = "slrn["; /* S,L,R,N are two-letter commands */
static int
mbx_parse(m)
struct mbx *m;
{
char *cp;
int i;
/* Translate entire buffer to lower case */
for (cp = m->line; *cp != '\0'; ++cp)
if (isupper(*cp))
*cp = tolower(*cp);
for (cp = m->line;isspace(*cp);++cp) ;/* Skip any spaces at the begining */
m->stype = ' ';
if (*cp != '\0' && *(cp+1) != '\0')
for(i=0; i<strlen(twocmds); ++i)
if (*cp == twocmds[i] && (isspace(*(cp+2)) || *(cp+2) == '\0'
|| *cp == '[')) {
if (islower(*(++cp)))
m->stype = toupper(*cp); /* Save the second character */
else m->stype = *cp;
*cp = ' ';
break;
}
return cmdparse(Mbcmds,m->line,(void *)m);
}
static void
mbx_getname(m)
struct mbx *m;
{
char *cp;
union sp sp;
char tmp[MAXSOCKSIZE];
int len = MAXSOCKSIZE;
getpeername(m->user,tmp,&len);
/* This is one of the two parts of the mbox code that depends on the
underlying protocol. We have to figure out the name of the
calling station. This is only practical when AX.25 or NET/ROM
is used. If we were using the mbox with TCP/IP one would
rather have to login in a manner similar to ftp.
*/
sp.p = tmp;
switch(sp.sa->sa_family){
case AF_NETROM:
case AF_AX25:
/* NETROM and AX25 socket address structures are "compatible" */
pax25(m->name,&sp.ax->ax25_addr) ;
cp = strchr(m->name,'-') ;
if (cp != NULLCHAR) /* get rid of SSID */
*cp = '\0' ;
/* case AF_INET: We need a gethostbyaddr() or login procedure first */
}
}
static int
dobye(argc,argv,p)
int argc;
char *argv[];
void *p;
{
struct mbx *m;
m = (struct mbx *)p;
close_s(m->user);
return 0;
}
static int
dochat(argc,argv,p)
int argc;
char *argv[];
void *p;
{
struct mbx *m;
struct proc *pp;
m = (struct mbx *)p;
pp = newproc("in_chat",2048,axnrhandle,m->user,(void *)m->type,NULL);
pwait(pp);
/* It returns only after a disconnect */
return 0;
}
/* Called every time a blank line is received. */
static int
donothing(argc,argv,p)
int argc;
char *argv[];
void *p;
{
return 0;
}
static int
dosend(argc,argv,p)
int argc;
char *argv[];
void *p;
{
int s;
char *host,fullfrom[80];
struct mbx *m;
m = (struct mbx *)p;
s = m->user;
if (mbx_to(argc,argv,m) == -1) {
if (m->sid & MBX_SID)
usprintf(s,"NO - syntax error\r") ;
else {
usprintf(s,"S command syntax error - format is:\r");
usprintf(s," S name [@ host] [< from_addr] [$bulletin_id]\r");
}
return 0;
}
if (validate_address(m->to) == 0){
if (m->sid & MBX_SID)
usprintf(s, "NO - bad address\r");
else
usprintf(s, "Bad user or host name\r");
/* We don't free any buffers here. They are freed upon the next
* call to mbx_to() or to dobye()
*/
return 0;
}
m->state = MBX_SUBJ ;
usprintf(s, (m->sid & MBX_SID) ? "OK\r" : "Subject:\r");
if (recvline(s,m->line,MBXLINE) == -1)
return 0;
rip(m->line);
if (mbx_data(m) == -1) {
usprintf(s,"Can't create temp file for mail\r") ;
return 0 ;
}
m->state = MBX_DATA ;
if ((m->sid & MBX_SID) == 0)
usprintf(s,
"Enter message. Terminate with /EX or ^Z in first column:\r");
while (recvline(s,m->line,MBXLINE) != -1) {
rip(m->line);
if (m->line[0] == 0x1a ||
strcmp(m->line, "/ex") == 0 ||
strcmp(m->line, "/EX") == 0) {
if ((host = strchr(m->to,'@')) == NULLCHAR)
host = Hostname ; /* use our hostname */
else
host++ ; /* use the host part of address */
/* make up full from name for work file */
(void)sprintf(fullfrom,"%s@%s",m->name,Hostname) ;
fseek(m->tfile,0L,0) ; /* reset to beginning */
if (queuejob(m->tfile,host,m->to,fullfrom) != 0)
usprintf(s, "Couldn't queue message for delivery\r");
break;
} else
fprintf(m->tfile,"%s\n",m->line) ; /* not done yet! */
}
fclose(m->tfile) ;
return 0 ;
}
static int
dosid(argc,argv,p)
int argc;
char *argv[];
void *p;
{
struct mbx *m;
m = (struct mbx *)p;
if (argc == 1)
return 1;
if (argv[1][strlen(argv[1]) - 1] != ']') /* must be an SID */
return 1;
m->sid = MBX_SID ;
/* Now check to see if this is an RLI board.
* As usual, Hank does it a bit differently from
* the rest of the world.
*/
if(m->stype == 'R' && strncmp(argv[1],"li",2) == 0)/* [RLI] at a minimum */
m->sid |= MBX_SID_RLI ;
return 0;
}
static int
dorevfwd(argc,argv,p)
int argc;
char *argv[];
void *p;
{
struct mbx *m;
m = (struct mbx *)p;
if (m->sid & MBX_SID) {
/* RLI BBS' expect us to disconnect if we
* have no mail for them, which of course
* we don't, being rather haughty about our
* protocol superiority.
*/
if (m->sid & MBX_SID_RLI)
dobye(0,NULL,m) ;
return 0;
}
return -1;
}
/* States for send line parser state machine */
#define LOOK_FOR_USER 2
#define IN_USER 3
#define AFTER_USER 4
#define LOOK_FOR_HOST 5
#define IN_HOST 6
#define AFTER_HOST 7
#define LOOK_FOR_FROM 8
#define IN_FROM 9
#define AFTER_FROM 10
#define LOOK_FOR_MSGID 11
#define IN_MSGID 12
#define FINAL_STATE 13
#define ERROR_STATE 14
/* Prepare the addressee. If the address is bad, return -1, otherwise
* return 0
*/
static int
mbx_to(argc,argv,p)
int argc;
char *argv[];
void *p;
{
register char *cp;
int state, i ;
char *user, *host, *from, *msgid ;
int userlen = 0, hostlen = 0, fromlen = 0, msgidlen = 0 ;
struct mbx *m ;
m = (struct mbx *)p;
/* Free anything that might be allocated
* since the last call to mbx_to()
*/
free(m->to) ;
m->to = NULLCHAR ;
free(m->tofrom) ;
m->tofrom = NULLCHAR ;
free(m->tomsgid) ;
m->tomsgid = NULLCHAR ;
if (argc == 1)
return -1;
i = 1;
cp = argv[i];
state = LOOK_FOR_USER ;
while (state < FINAL_STATE) {
#ifdef MBDEBUG
printf("State is %d, char is %c\n", state, *cp) ;
#endif
switch (state) {
case LOOK_FOR_USER:
if (*cp == '@' || *cp == '<' || *cp == '$')
state = ERROR_STATE ; /* no user */
else {
user = cp ; /* point at start */
userlen++ ; /* start counting */
state = IN_USER ;
}
break ;
case IN_USER:
switch (*cp) {
case '\0':
state = AFTER_USER ; /* done with username */
break ;
case '@':
state = LOOK_FOR_HOST ; /* hostname should follow */
break ;
case '<':
state = LOOK_FOR_FROM ; /* from name should follow */
break ;
case '$':
state = LOOK_FOR_MSGID ; /* message id should follow */
break ;
default:
userlen++ ; /* part of username */
}
break ;
case AFTER_USER:
switch (*cp) {
case '@':
state = LOOK_FOR_HOST ; /* hostname follows */
break ;
case '<':
state = LOOK_FOR_FROM ; /* fromname follows */
break ;
case '$':
state = LOOK_FOR_MSGID ; /* message id follows */
break ;
default:
state = ERROR_STATE ;
}
break ;
case LOOK_FOR_HOST:
if (*cp == '@' || *cp == '<' || *cp == '$') {
state = ERROR_STATE;
break;
}
if (*cp == '\0')
break;
host = cp ;
hostlen++ ;
state = IN_HOST ;
break ;
case IN_HOST:
switch (*cp) {
case '\0':
state = AFTER_HOST ; /* found user@host */
break ;
case '@':
state = ERROR_STATE ; /* user@host@? */
break ;
case '<':
state = LOOK_FOR_FROM ; /* fromname follows */
break ;
case '$':
state = LOOK_FOR_MSGID ; /* message id follows */
break ;
default:
hostlen++ ;
}
break ;
case AFTER_HOST:
switch (*cp) {
case '@':
state = ERROR_STATE ; /* user@host @ */
break ;
case '<':
state = LOOK_FOR_FROM ; /* user@host < */
break ;
case '$':
state = LOOK_FOR_MSGID ; /* user@host $ */
break ;
default:
state = ERROR_STATE ; /* user@host foo */
}
break ;
case LOOK_FOR_FROM:
if (*cp == '@' || *cp == '<' || *cp == '$') {
state = ERROR_STATE;
break;
}
if (*cp == '\0')
break;
from = cp ;
fromlen++ ;
state = IN_FROM ;
break ;
case IN_FROM:
switch (*cp) {
case '\0':
state = AFTER_FROM ; /* user@host <foo */
break ;
case '<':
state = ERROR_STATE ; /* user@host <foo< */
break ;
case '$':
state = LOOK_FOR_MSGID ; /* message id follows */
break ;
default:
fromlen++ ;
}
break ;
case AFTER_FROM:
switch (*cp) {
case '@': /* user@host <foo @ */
case '<': /* user@host <foo < */
state = ERROR_STATE ;
break ;
case '$':
state = LOOK_FOR_MSGID ; /* user@host <foo $ */
break ;
default:
state = ERROR_STATE ; /* user@host foo */
}
break ;
case LOOK_FOR_MSGID:
if (*cp == '\0')
break;
msgid = cp ;
msgidlen++ ;
state = IN_MSGID ;
break ;
case IN_MSGID:
if (*cp == '\0')
state = FINAL_STATE ;
else
msgidlen++ ;
break ;
default:
/* what are we doing in this state? */
state = ERROR_STATE ;
}
if (*(cp) == '\0') {
++i;
if (i < argc)
cp = argv[i];
else break;
}
else ++cp;
}
if (state == ERROR_STATE || state == LOOK_FOR_HOST
|| state == LOOK_FOR_FROM || state == LOOK_FOR_MSGID)
return -1 ; /* syntax error */
if ((m->to = malloc(userlen + hostlen + 2)) == NULLCHAR)
return -1 ; /* no room for to address */
strncpy(m->to, user, userlen) ;
m->to[userlen] = '\0' ;
if (hostlen) {
m->to[userlen] = '@' ;
strncpy(m->to + userlen + 1, host, hostlen) ;
m->to[userlen + hostlen + 1] = '\0' ;
}
if (fromlen) {
if ((m->tofrom = malloc(fromlen + 1)) == NULLCHAR) {
free(m->to) ;
m->to = NULLCHAR ;
return -1 ;
}
strncpy(m->tofrom, from, fromlen) ;
m->tofrom[fromlen] = '\0' ;
}
if (msgidlen) {
if ((m->tomsgid = malloc(msgidlen + 1)) == NULLCHAR) {
free(m->to) ;
m->to = NULLCHAR ;
free(m->tofrom) ;
m->tofrom = NULLCHAR ;
return -1 ;
}
strncpy(m->tomsgid, msgid, msgidlen) ;
m->tomsgid[msgidlen] = '\0' ;
}
return 0 ;
}
/* This opens the data file and writes the mail header into it.
* Returns 0 if OK, and -1 if not.
*/
static int
mbx_data(m)
struct mbx *m ;
{
time_t t, time() ;
char *ptime() ;
extern FILE *tmpfile();
extern long get_msgid() ;
if ((m->tfile = tmpfile()) == NULLFILE)
return -1 ;
time(&t) ;
fprintf(m->tfile,"Date: %s",ptime(&t)) ;
if (m->tomsgid)
fprintf(m->tfile,"Message-Id: <%s@%s.bbs>\n", m->tomsgid, m->name) ;
else
fprintf(m->tfile,"Message-Id: <%ld@%s>\n",get_msgid(),Hostname);
fprintf(m->tfile,"From: %s%%%s.bbs@%s\n",
m->tofrom ? m->tofrom : m->name, m->name, Hostname) ;
fprintf(m->tfile,"To: %s\n",m->to) ;
fprintf(m->tfile,"Subject: %s\n",m->line) ;
if (!isspace(m->stype))
fprintf(m->tfile,"X-BBS-Msg-Type: %c\n", m->stype) ;
fprintf(m->tfile,"\n") ;
return 0 ;
}